#include "ssd1312.h"
#include "STC8G_H_Delay.h"
#include "STC8G_H_GPIO.h"
#include "OLED_Data.h"

sbit SCL = P2 ^ 5;
sbit SDA = P2 ^ 4;

void SSD1312_IO_config(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.Pin = GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5;
    GPIO_InitStructure.Mode = GPIO_PullUp;
    GPIO_Inilize(GPIO_P2, &GPIO_InitStructure);
}

void OLED_W_SCL(uint8 BitValue)
{
    /*根据BitValue的值，将SCL置高电平或者低电平*/
    SCL = BitValue;
    // delay_us(1);
    /*如果单片机速度过快，可在此添加适量延时，以避免超出I2C通信的最大速度*/
    //...
}
void OLED_W_SDA(uint8 BitValue)
{
    /*根据BitValue的值，将SDA置高电平或者低电平*/
    SDA = BitValue;
    // delay_us(1);

    /*如果单片机速度过快，可在此添加适量延时，以避免超出I2C通信的最大速度*/
    //...
}
void OLED_I2C_Start(void)
{
    OLED_W_SDA(1); // 释放SDA，确保SDA为高电平
    OLED_W_SCL(1); // 释放SCL，确保SCL为高电平
    OLED_W_SDA(0); // 在SCL高电平期间，拉低SDA，产生起始信号
    OLED_W_SCL(0); // 起始后把SCL也拉低，即为了占用总线，也为了方便总线时序的拼接
}
void OLED_I2C_Stop(void)
{
    SDA = 0;     // 拉低数据线
    SCL = 1;     // 拉高时钟线
    delay_us(1); // 延时
    SDA = 1;     // 产生上升沿
    delay_us(1); // 延时
}
// 测试通信是否应答用。
char OLED_I2C_RecvACK(void)
{
    SCL = 1;     // 拉高时钟线
    delay_us(1); // 延时
    CY = SDA;    // 读应答信号
    SCL = 0;     // 拉低时钟线
    delay_us(1); // 延时
    return CY;
}
/**
 * 函    数：I2C发送一个字节
 * 参    数：Byte 要发送的一个字节数据，范围：0x00~0xFF
 * 返 回 值：无
 */
void OLED_I2C_SendByte(uint8 Byte)
{
    uint8 i;
    /*循环8次，主机依次发送数据的每一位*/
    for (i = 0; i < 8; i++)
    {
        /*使用掩码的方式取出Byte的指定一位数据并写入到SDA线*/
        /*两个!的作用是，让所有非零的值变为1*/
        OLED_W_SDA(!!(Byte & (0x80 >> i)));
        OLED_W_SCL(1); // 释放SCL，从机在SCL高电平期间读取SDA
        OLED_W_SCL(0); // 拉低SCL，主机开始发送下一位数据
    }

    OLED_W_SCL(1); // 额外的一个时钟，不处理应答信号，测试时OLED_I2C_RecvACK代替
    OLED_W_SCL(0);
}
// 测试通信是否应答用。
int OLED_IIC_TEST(void)
{
    int Ack;
    OLED_I2C_Start();
    OLED_I2C_SendByte(0x78);
    Ack = OLED_I2C_RecvACK();
    OLED_I2C_Stop();
    return Ack;
}
//========================================================================
/**
 * 函    数：OLED写命令
 * 参    数：Command 要写入的命令值，范围：0x00~0xFF
 * 返 回 值：无
 */
void OLED_WriteCommand(uint8 Command)
{
    OLED_I2C_Start();           // I2C起始
    OLED_I2C_SendByte(0x78);    // 发送OLED的I2C从机地址
    OLED_I2C_SendByte(0x00);    // 控制字节，给0x00，表示即将写命令
    OLED_I2C_SendByte(Command); // 写入指定的命令
    OLED_I2C_Stop();            // I2C终止
}
void OLED_WriteData(uint8 Data)
{
    OLED_I2C_Start();        // I2C起始
    OLED_I2C_SendByte(0x78); // 发送OLED的I2C从机地址
    OLED_I2C_SendByte(0x40); // 控制字节，给0x00，表示即将写命令
    OLED_I2C_SendByte(Data); // 写入指定的命令
    OLED_I2C_Stop();         // I2C终止
}
/*********************通信协议*/

/**
 * 函    数：OLED设置显示光标位置
 * 参    数：Page 指定光标所在的页，范围：0~7
 * 参    数：X 指定光标所在的X轴坐标，范围：0~127
 * 返 回 值：无
 * 说    明：OLED默认的Y轴，只能8个Bit为一组写入，即1页等于8个Y轴坐标
 */
void OLED_SetCursor(uint8 X, uint8 Page)
{
    /*如果使用此程序驱动1.3寸的OLED显示屏，则需要解除此注释*/
    /*因为1.3寸的OLED驱动芯片（SH1106）有132列*/
    /*屏幕的起始列接在了第2列，而不是第0列*/
    /*所以需要将X加2，才能正常显示*/
    // X += 2;

    /*通过指令设置页地址和列地址*/
    OLED_WriteCommand(0xB0 | Page);              // 设置页位置
    OLED_WriteCommand(0x10 | ((X & 0xF0) >> 4)); // 设置X位置高4位
    OLED_WriteCommand(0x00 | (X & 0x0F));        // 设置X位置低4位
}
// X 128  Y 8 pagae
void OLED_ShowChar(uint8 X, uint8 Y, char Char, uint8 FontSize)
{
    uint8 i;
    if (FontSize == 32)
    {
        OLED_SetCursor(X, Y);
        for (i = 0; i < 16; i++)
            OLED_WriteData(led_32x16[Char - '0'][i]);
        OLED_SetCursor(X, Y+1);
        for (i = 0; i < 16; i++)
            OLED_WriteData(led_32x16[Char - '0'][i+16]);
        OLED_SetCursor(X, Y+2);
        for (i = 0; i < 16; i++)
            OLED_WriteData(led_32x16[Char - '0'][i+32]);
        OLED_SetCursor(X, Y+3);
        for (i = 0; i < 16; i++)
            OLED_WriteData(led_32x16[Char - '0'][i+48]);
    }
    if (FontSize == 64)
    {
        OLED_SetCursor(X, 0);
        for (i = 0; i < 32; i++)
            OLED_WriteData(led_64x32[Char - '0'][i]);
        OLED_SetCursor(X, 1);
        for (i = 0; i < 32; i++)
            OLED_WriteData(led_64x32[Char - '0'][i + 32]);
        OLED_SetCursor(X, 2);
        for (i = 0; i < 32; i++)
            OLED_WriteData(led_64x32[Char - '0'][i + 64]);
        OLED_SetCursor(X, 3);
        for (i = 0; i < 32; i++)
            OLED_WriteData(led_64x32[Char - '0'][i + 96]);
        OLED_SetCursor(X, 4);
        for (i = 0; i < 32; i++)
            OLED_WriteData(led_64x32[Char - '0'][i + 128]);
        OLED_SetCursor(X, 5);
        for (i = 0; i < 32; i++)
            OLED_WriteData(led_64x32[Char - '0'][i + 160]);
        OLED_SetCursor(X, 6);
        for (i = 0; i < 32; i++)
            OLED_WriteData(led_64x32[Char - '0'][i + 192]);
        OLED_SetCursor(X, 7);
        for (i = 0; i < 32; i++)
            OLED_WriteData(led_64x32[Char - '0'][i + 224]);
    }
     
}
void OLED_ShowString(uint8 X, uint8 Y, char *String, uint8 FontSize)
{
    uint8 i;
    int offset = 0;
    OLED_SetCursor(X, 0);
    for (i = 0; String[i] != '\0'; i++)
    {
        if(String[i] == '.')
        {
            if(FontSize == 64){
                show64_point(X + offset);
                offset+= 16;
            }
            if(FontSize == 32)
            {
                show32_point(X + offset, Y);
                offset+= 8; 
            }
        }else{
            OLED_ShowChar(X + offset, Y, String[i], FontSize);
            offset+=  FontSize / 2;
        }
    }
}

void OLED_Clear(void)
{
    uint8 i, j;
    for (j = 0; j < 8; j++) // 遍历8页
    {
        OLED_SetCursor(0, j);
        for (i = 0; i < 128; i++) // 遍历128列
        {
            OLED_WriteData(0x00);
        }
    }
}

/*工具函数*********************/
/*工具函数仅供内部部分函数使用*/
/**
 * 函    数：次方函数
 * 参    数：X 底数
 * 参    数：Y 指数
 * 返 回 值：等于X的Y次方
 */
uint32 OLED_Pow(uint32 X, uint32 Y)
{
    uint32 Result = 1; // 结果默认为1
    while (Y--)        // 累乘Y次
    {
        Result *= X; // 每次把X累乘到结果上
    }
    return Result;
}

void show64_point(u8 X)
{
    u8 i;
    OLED_SetCursor(X, 0);
    for (i = 0; i < 16; i++)
        OLED_WriteData(led_64x32[10][i]);
    OLED_SetCursor(X, 1);
    for (i = 0; i < 16; i++)
        OLED_WriteData(led_64x32[10][i + 16]);
    OLED_SetCursor(X, 2);
    for (i = 0; i < 16; i++)
        OLED_WriteData(led_64x32[10][i + 32]);
    OLED_SetCursor(X, 3);
    for (i = 0; i < 16; i++)
        OLED_WriteData(led_64x32[10][i + 48]);
    OLED_SetCursor(X, 4);
    for (i = 0; i < 16; i++)
        OLED_WriteData(led_64x32[10][i + 64]);
    OLED_SetCursor(X, 5);
    for (i = 0; i < 16; i++)
        OLED_WriteData(led_64x32[10][i + 80]);
    OLED_SetCursor(X, 6);
    for (i = 0; i < 16; i++)
        OLED_WriteData(led_64x32[10][i + 96]);
    OLED_SetCursor(X, 7);
    for (i = 0; i < 16; i++)
        OLED_WriteData(led_64x32[10][i + 112]);
}

void show32_point(u8 X,u8 Y)
{
    u8 i;
    OLED_SetCursor(X, Y);
    for (i = 0; i < 8; i++)
        OLED_WriteData(led_32x16[13][i]);
    OLED_SetCursor(X, Y+1);
    for (i = 0; i < 8; i++)
        OLED_WriteData(led_32x16[13][i + 8]);
    OLED_SetCursor(X, Y+2);
    for (i = 0; i < 8; i++)
        OLED_WriteData(led_32x16[13][i + 16]);
    OLED_SetCursor(X, Y+3);
    for (i = 0; i < 8; i++)
        OLED_WriteData(led_32x16[13][i + 24]);
}
void show32_2point(u8 X,u8 Y)
{
    u8 i;
    OLED_SetCursor(X, Y);
    for (i = 0; i < 8; i++)
        OLED_WriteData(led_32x16[13][i+32]);
    OLED_SetCursor(X, Y+1);
    for (i = 0; i < 8; i++)
        OLED_WriteData(led_32x16[13][i + 8+32]);
    OLED_SetCursor(X, Y+2);
    for (i = 0; i < 8; i++)
        OLED_WriteData(led_32x16[13][i + 16+32]);
    OLED_SetCursor(X, Y+3);
    for (i = 0; i < 8; i++)
        OLED_WriteData(led_32x16[13][i + 24+32]);
}
void show32_icon(u8 X,u8 Y,u8 *ch)
{
    u8 i;
    OLED_SetCursor(X, Y);
    for (i = 0; i < 32; i++)
        OLED_WriteData(ch[i]);
    OLED_SetCursor(X, Y+1);
    for (i = 0; i < 32; i++)
        OLED_WriteData(ch[i+32]);
    OLED_SetCursor(X, Y+2);
    for (i = 0; i < 32; i++)
        OLED_WriteData(ch[i+64]);
    OLED_SetCursor(X, Y+3);
    for (i = 0; i < 32; i++)
        OLED_WriteData(ch[i+96]);
}
/*硬件配置*********************/

/**
 * 函    数：OLED初始化
 * 参    数：无
 * 返 回 值：无
 * 说    明：使用前，需要调用此初始化函数
 */
void OLED_Init(void)
{
    SSD1312_IO_config();

    OLED_SW = 1;
    delay_ms(200);
    OLED_SW = 0;

    /*写入一系列的命令，对OLED进行初始化配置*/
    OLED_WriteCommand(0xAE); // 设置显示开启/关闭，0xAE关闭，0xAF开启

    OLED_WriteCommand(0x00); /*set lower column address*/
    OLED_WriteCommand(0x10); /*set higher column address*/

    OLED_WriteCommand(0xB0); // /*set page address*/

    OLED_WriteCommand(0x81); // contract control
    OLED_WriteCommand(0x5f); // 128

    if (USE_HORIZONTAL == 0)
    {
        OLED_WriteCommand(0x20); // Set Memory addressing mode (0x20/0x21)
        OLED_WriteCommand(0x09); // 128

        OLED_WriteCommand(0xA1); // set segment remap  0XA1
        OLED_WriteCommand(0xC8); // Com scan direction   0Xc8
    }
    else if (USE_HORIZONTAL == 90)
    {
        OLED_WriteCommand(0x20); //
        OLED_WriteCommand(0x02); //
        OLED_WriteCommand(0xA1); //
        OLED_WriteCommand(0xC0); //
    }
    else if (USE_HORIZONTAL == 180)
    {
        OLED_WriteCommand(0x20);
        OLED_WriteCommand(0x09);
        OLED_WriteCommand(0xA0);
        OLED_WriteCommand(0xC0);
    }
    else if (USE_HORIZONTAL == 270)
    {
        OLED_WriteCommand(0x20);
        OLED_WriteCommand(0x02);
        OLED_WriteCommand(0xA0);
        OLED_WriteCommand(0xC8);
    }

    OLED_WriteCommand(0xA4); /*Disable Entire Display On (0xA4/0xA5)*/

    OLED_WriteCommand(0xA6); /*normal / reverse*/

    OLED_WriteCommand(0xA8); /*multiplex ratio*/
    OLED_WriteCommand(0x3F); /*duty = 1/64*/

    OLED_WriteCommand(0xD3); /*set display offset*/
    OLED_WriteCommand(0x00); /*   0x20   */

    OLED_WriteCommand(0xD5); /*set osc division*/
    OLED_WriteCommand(0x80);

    OLED_WriteCommand(0xD9); /*set pre-charge period*/
    OLED_WriteCommand(0x22);

    OLED_WriteCommand(0xDA); /* Set SEG Pins Hardware Configuration */
    OLED_WriteCommand(0x10);

    OLED_WriteCommand(0xDB); /*set vcomh*/
    OLED_WriteCommand(0x30);

    OLED_WriteCommand(0x8D); /*set charge pump enable*/
    OLED_WriteCommand(0x72); /* 0x12:7.5V; 0x52:8V;  0x72:9V;  0x92:10V */

    OLED_Clear();
    OLED_WriteCommand(0xAF);
    OLED_SW = 1;
}